package simulator;

/**
 * Trida reprezentujici trasu nakladniho vozu. Trasa je reprezentovana jednou instanci tridy <code>Path</code>, tedy cestou.
 * @author Petr Altman
 *
 */
public class TruckPath {

	private Path path = new Path();
	
	/**
	 * Nastavi novou cestu trasy a prepocte veskere udaje.
	 * @param path Nova cesta trasy.
	 * @param actualTime Referencni aktualni cas.
	 */
	public void setPath(Path path, int actualTime) {
		this.path = path;
		
		this.wayTime = path.getWayTime();
		this.length = path.getLength();
		
		setStartTime(order.getOwner().getWorktimeStart() - getWayTimeAbs(), actualTime);
	}
		
	/**
	 * Vrati cestu trasy.
	 * @return Cesta trasy.
	 */
	public final Path getPath() {
		return path;
	}

	// doba potrebna pro projeti teto cesty
	private int wayTime;
	/**
	 * Vrati dobu v sekundach potrebnou pro projeti teto trasy.
	 * @return Potrebna doba pro projeti trasy.
	 */
	public int getWayTime() {
		return wayTime;
	}
	
	/**
	 * Vrati cas, ktery bude po projeti trasy v sekundach.
	 * @return Cas po projeti trasy.
	 */
	public int getWayTimeAbs() {
		return getStartTime() + getWayTime();
	}

	private int length;
	/**
	 * Vrati delku trasy v metrech.
	 * @return
	 */
	public int getLength() {
		return length;
	}

	private int startTime;
	/**
	 * Vrati cas, kdy nakladak vyrazi na cestu. Tento cas je absolutni.
	 * @return Absolutni cas kdy nakladak vyrazi na cestu.
	 */
	public int getStartTime() {
		return startTime;
	}

	/**
	 * Nastavi cas, ve ktery nakladak vyrazi na cestu. Tento cas je absolutni.
	 * @param startTime Absolutni cas, kdy nakladak vyrazi na cestu.
	 * @param actualTime Referencni aktualni cas.
	 */
	public void setStartTime(int startTime, int actualTime) {
		this.startTime = startTime;
		
		if(startTime < actualTime)
			this.startTime = actualTime;
		
		// vypocet doby cekani
		int wt = order.getOwner().getWorktimeStart() - (getWayTimeAbs());
		isLateUnload = (wt < 0);
		unloadDelay = 0;
		if(isLateUnload) {
			unloadDelay = -wt;
			wt = 0;
		}
		waitTime  = wt;
	}

	private int waitTime;
	/**
	 * Usek casu, ktery nakladak ceka pred vylozenim. Tento usek neni nikdy zaporny.
	 * @return Usek casu ktery nakladak ceka.
	 */
	public int getWaitTime() {
		return waitTime;
	}
	
	/**
	 * Vrati cas, kdy nakladak bude pripraven na vykladku. Tento cas je absolutni.
	 * @return Absolutni cas, kdy nakladak bude pripraven na vykladku.
	 */
	public int getWaitTimeAbs() {
		return getWayTimeAbs() + getWaitTime();
	}

	/**
	 * Vrati true pokud lze casove splnit objednavku.
	 * @return true kdyz je mozne objednavku splnit, jinak false.
	 */
	public boolean isTimeAcceptable() {
//		return Math.abs(order.owner.worktimeStart - (getWayTime() + getStartTime())) < (order.owner.worktimeEnd - order.owner.worktimeStart);
		return isTimeAcceptable(getStartTime());
	}
	
	/**
	 * Vrati true pokud lze casove splnit objednavku na zaklade daneho casu.
	 * @param time Referencni cas.
	 * @return true kdyz je mozne objednavku splnit, jinak false.
	 */
	public boolean isTimeAcceptable(int time) {
		return time + getWayTime() <= order.getOwner().getWorktimeStart() + Order.MAX_UNLOAD_DELAY; //
//		return true;
	}
	
	private Order order;
	/**
	 * Priradi trase objednavku.
	 * @param order Objednavka k priprazeni trase.
	 */
	public void setOrder(Order order) {
		this.order = order;
	}

	/**
	 * Vrat instanci objdnavky priprazene trase.
	 * @return Objednavka priprazena trase.
	 */
	public Order getOrder() {
		return order;
	}

	private boolean isLateUnload = false;
	/**
	 * Zjisti, zda se jedna o pozdni vykladku, respektive zda nakladni vuz prijede na cilove misto pozde.
	 * @return True zda se jedna o pozdni vykladku, jinak false.
	 */
	public boolean isLateUnload() {
		return isLateUnload;
	}

	private int unloadDelay = 0;
	
	/**
	 * Cstor.
	 * @param order Objednavka priprazena teto trase.
	 */
	public TruckPath(Order order) {
		super();
		this.order = order;
	}
	
	/**
	 * Cstor.
	 */
	public TruckPath() {
		super();
	}
	
	/**
	 * Vrati usek casu, ktery nakladak provadi vykladku.
	 * @return Usek casu vykladky.
	 */
	public int getUnloadingTime() {
		int time = order.getGoodsCount() * Company.TIME_UNLOAD_ONE + (isLateUnload ? unloadDelay : 0);
		return time;
	}
	
	/**
	 * Vrati cas, kdy bude mit nakladni vuz hotovou vykladku. 
	 * @return Cas, kdy bude vykladka dokoncena.
	 */
	public int getUnloadingTimeAbs() {
		return getWaitTimeAbs() + getUnloadingTime();
	}
	
	/**
	 * Vrati usek casu, ktery je zapotrebi pro splneni teto cesty.
	 * @return
	 */
	public int getTotalTime() {
		return wayTime + waitTime + getUnloadingTime();
	}
	
	/**
	 * Vrati cas, kdy bude tato cesta splnena. Tento cas je absolutni.
	 * @return Absolutni cas, kdy bude tato cesta splnena.
	 */
	public int getEndTime() {
		return getStartTime() + getTotalTime();
	}
	
	@Override
	public String toString() {
		return getStartTime() + "; " + getWayTimeAbs() + "; " + getWaitTimeAbs() + "; " + getEndTime() + "; " + order.getOwner().getWorktimeStart() + "; " + order.getOwner().getWorktimeEnd();
	}
}
